#include "ezqhttp.h"
#include <QEventLoop>
#include "http/ezqhttpaccessmanager.h"
#include <QFile>
#include <QDataStream>
#include "log/EZQLOG.h"

using namespace EZQHTTPNS;

EZQHttp::EZQHttp() :
    QObject(0)
{
    _request = 0;
    _reply = 0;
    _receiveByteLen = 0;
    _respondTotalSize = 0;
    _responseCode = 0;
    _method = QString("GET");
    _isNeedProgress = false;
    _cacheReciveByteLen = 5 * (1024*1024);
//    setStatus(HttpStatus_ini);
    _status = HttpStatus_init;
    _accessmanager = EZQHttpAccessManager::shareManager()->networkAccessManager();
    connect(_accessmanager,SIGNAL(finished(QNetworkReply*)),this,SLOT(psl_httpFinish(QNetworkReply*)));
    reset();
}

EZQHttp::~EZQHttp()
{
    EZDebug << "~Http" << _url;
    disconnect(this);
    cancel();

}

QString EZQHttp::url() const
{
    return _url;
}

void EZQHttp::setUrl(const QString &url)
{
    _url = url;
    _request->setUrl(QUrl(url));
    _postByte = QByteArray();
}

void EZQHttp::reset()
{
    if(_request){
        delete _request;
    }
    _request = new QNetworkRequest();
    _responseCode = 0;

    _receiveByte.clear();
    _receiveByteLen = 0;
    _respondTotalSize = 0;
    _responseCode = 0;
    cancel();
    setStatus(HttpStatus_init);
}

void EZQHttp::cancel()
{
    bool isRelease = false;
    if(_status == HttpStatus_runing){
        setStatus(HttpStatus_cancel);
        _reply->abort();
        isRelease = true;
    }
    if(_reply){
        disconnect(_reply);
        delete _reply;
        _reply = 0;
    }
    if(isRelease){
        Release();
    }

}
void EZQHttp::setStatus(const HttpStatus &status)
{
    _status = status;
    emit statusChange(status);
}

HttpStatus EZQHttp::status()
{
    return _status;
}

void EZQHttp::startAsync()
{
    setStatus(HttpStatus_start);
    setStatus(HttpStatus_runing);
    startRequest();
}
void EZQHttp::startRequest()
{
    Retain();
    _receiveByte.clear();
    _receiveByteLen = 0;
    if(QString::compare(QString("GET"),_method)==0){
        _reply = _accessmanager->get(*_request);
    }else{
        _reply = _accessmanager->post(*_request,_postByte);
    }
    if(_isNeedProgress==true){
        connect(_reply,SIGNAL(downloadProgress(qint64,qint64)),this,SLOT(psl_downloadProgress(qint64,qint64)));
    }
}

void EZQHttp::startSync()
{
    QEventLoop loop;
    connect(_accessmanager,SIGNAL(finished(QNetworkReply*)),&loop,SLOT(quit()));
    startAsync();
    loop.exec();
}

void EZQHttp::setHeader(const QString &key, const QString &value)
{
    QByteArray byteKey;
    byteKey.append(key);
    QByteArray byteValue;
    byteValue.append(value);
    _request->setRawHeader(byteKey,byteValue);
}
void EZQHttp::setHeader(QNetworkRequest::KnownHeaders type, QString value)
{
    _request->setHeader(type,value);
}
void EZQHttp::addPostValue(const QString &key, const QString &value)
{
//    _request->po
    if(_postByte.length()>0){
        _postByte.append("&");
    }
    _postByte.append(key+"="+value);
}

void EZQHttp::psl_downloadProgress(qint64 bytesReceived, qint64 bytesTotal)
{
    _mutex.lock();
    int len = bytesReceived - _receiveByteLen;
    if(len > 0){
        QByteArray nrbytes = _reply->readAll();
        _receiveByte.append(nrbytes);
        _receiveByteLen += nrbytes.length();
        _respondTotalSize = bytesTotal;
        if(_downLoadPath.length() > 0 && _receiveByte.length() >= _cacheReciveByteLen){
            saveToPath();
        }

    }
    _mutex.unlock();
    if(len > 0){
        emit downloadProgress(bytesReceived,bytesTotal);
    }

}
QString EZQHttp::downLoadPath() const
{
    return _downLoadPath;
}

void EZQHttp::setDownLoadPath(const QString &downLoadPath)
{
    setNeedProgress(true);
//    QFile file(downLoadPath);
//    file.remove();
    QFile::remove(downLoadPath);
    _downLoadPath = downLoadPath;
}

bool EZQHttp::isNeedProgress() const
{
    return _isNeedProgress;
}

void EZQHttp::setNeedProgress(bool isNeed)
{
    _isNeedProgress = isNeed;
}


void EZQHttp::psl_httpFinish(QNetworkReply*reply)
{
    if(reply != _reply){ //not current request
        return;
    }
    int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
    if(_reply->error() == QNetworkReply::NoError){
        _responseCode = statusCode;
        if(statusCode==302){
            QString strUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toString();
            _request->setUrl(QUrl(strUrl));
            _postByte = QByteArray();
            _reply = _accessmanager->get(*_request);
            if(_isNeedProgress==true){
                connect(_reply,SIGNAL(downloadProgress(qint64,qint64)),this,SLOT(psl_downloadProgress(qint64,qint64)));
            }
            EZDebug << "bejin url jump ";
        }else{
            setStatus(HttpStatus_finish);
        }
    }else{
        _responseCode = -1;
        if(_status == HttpStatus_runing){
            setStatus(HttpStatus_error);
        }

    }

    if(statusCode==302){
        disconnect(reply);
        delete reply;
    }else{
        emit finish();
        if(_status != HttpStatus_cancel){
            Release();
        }

    }

}
QString EZQHttp::method() const
{
    return _method;
}

void EZQHttp::setMethod(const QString &method)
{
    _method = method;
}

QByteArray EZQHttp::responseBytes()
{
    _mutex.lock();
    _receiveByte.append(_reply->readAll());
    if(_downLoadPath.length() > 0){
        saveToPath();
    }
    _mutex.unlock();
    return _receiveByte;
}

void EZQHttp::saveToPath()
{
    QFile file(_downLoadPath);
    if(file.open(QIODevice::Append)){
//        QDataStream stream(&file);
//        stream << _receiveByte.data();
        file.write(_receiveByte.data(),_receiveByte.length());
        _receiveByte.clear();
        file.close();
    }
}
qint64 EZQHttp::respondTotalSize() const
{
    return _respondTotalSize;
}

void EZQHttp::setRespondTotalSize(const qint64 &respondTotalSize)
{
    _respondTotalSize = respondTotalSize;
}

qint64 EZQHttp::readBytes(char *buf,const qint64 &offset,const qint64 &bufLen)
{
    QMutexLocker locker(&_mutex);
    int readLen = _receiveByteLen - offset;
    readLen = readLen > bufLen ? bufLen:readLen;
    int readFilelen = 0;
    int fileLen = _receiveByteLen - _receiveByte.length();
    if( fileLen > offset){ //read from file
        readFilelen = fileLen - offset;
        readFilelen = readFilelen > readLen ? readLen:readFilelen;
        QFile file(_downLoadPath);
        if(file.open(QIODevice::ReadOnly)){
            int rflen = file.read(buf,readFilelen);
            if(rflen != readFilelen){
                qDebug() << "EZQHttp::readBytes error want read:" << readFilelen << "but return:" << rflen;
            }
        }else{
            qDebug() << "EZQHttp::readBytes error can not open file";
        }
    }
    if(readFilelen < readLen){
        int offset2 = fileLen < offset ? offset-fileLen : 0;
        memcpy(buf+readFilelen,_receiveByte.data()+offset2,readLen-readFilelen);
    }
    return readLen;
}

qint64 EZQHttp::receiveByteLen()
{
    _mutex.lock();
    qint64 len = _receiveByteLen;
    _mutex.unlock();
    return len;
}

void EZQHttp::setReceiveByteLen(const qint64 &receiveByteLen)
{
    _receiveByteLen = receiveByteLen;
}
int EZQHttp::responseCode() const
{
    return _responseCode;
}

void EZQHttp::setResponseCode(int responseCode)
{
    _responseCode = responseCode;
}




